/**
    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) 2010  Sean Beecroft

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 * @version 1.10 2010-01-01
 * @author Sean Beecroft, Charles Bell
 */

package yawiki.client.editors;

/**
 *	@author: Charles Bell
 *	@version: May 27, 2002
 *
 *  http://www.artima.com/forums/flat.jsp?forum=1&thread=1276	
 */



import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import javax.swing.*;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;


import java.awt.*;
import javax.swing.*;

import yawiki.client.filters.YHTMLFileFilter;


public class YDesignEditor extends JPanel implements ActionListener {

	private HTMLDocument document;
	private JTextPane textPane = new JTextPane();
	private boolean debug = false;
	private File currentFile;

	/** Listener for the edits on the current document. */
	protected UndoableEditListener undoHandler = new UndoHandler();

	/** UndoManager that we add edits to. */
	protected UndoManager undo = new UndoManager();
	private UndoAction undoAction = new UndoAction();
	private RedoAction redoAction = new RedoAction();
	private Action cutAction = new DefaultEditorKit.CutAction();
	private Action copyAction = new DefaultEditorKit.CopyAction();
	private Action pasteAction = new DefaultEditorKit.PasteAction();
	private Action boldAction = new StyledEditorKit.BoldAction();
	private Action underlineAction = new StyledEditorKit.UnderlineAction();
	private Action italicAction = new StyledEditorKit.ItalicAction();
	private Action insertBreakAction = new DefaultEditorKit.InsertBreakAction();
	private HTMLEditorKit.InsertHTMLTextAction unorderedListAction = new HTMLEditorKit.InsertHTMLTextAction(
			"Bullets", "<ul><li> </li></ul>", HTML.Tag.P, HTML.Tag.UL);

	private HTMLEditorKit.InsertHTMLTextAction bulletAction = new HTMLEditorKit.InsertHTMLTextAction(
			"Bullets", "<li> </li>", HTML.Tag.UL, HTML.Tag.LI);
	private HTMLEditorKit.InsertHTMLTextAction tableAction = new HTMLEditorKit.InsertHTMLTextAction(
			"Table", "<TABLE> </TABLE>", HTML.Tag.BODY, HTML.Tag.TABLE);
	private HTMLEditorKit.InsertHTMLTextAction tableRowAction = new HTMLEditorKit.InsertHTMLTextAction(
			"Table Row", "<TR> </TR>", HTML.Tag.TABLE, HTML.Tag.TR);
	private HTMLEditorKit.InsertHTMLTextAction tableCellAction = new HTMLEditorKit.InsertHTMLTextAction(
			"Table Cell", "<TD> </TD>", HTML.Tag.TR, HTML.Tag.TD);
	private HTMLEditorKit.InsertHTMLTextAction linkAction = new HTMLEditorKit.InsertHTMLTextAction("Hyper Link", "<a href=\"\">text</a>", HTML.Tag.BODY, HTML.Tag.A);
	

	public YDesignEditor() {
		//super("HTMLDocumentEditor");
		HTMLEditorKit editorKit = new HTMLEditorKit();
		document = (HTMLDocument) editorKit.createDefaultDocument();
		// Force SwingSet to come up in the Cross Platform L&F
		//try {
			// UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
			// If you want the System L&F instead, comment out the above line
			// and
			// uncomment the following:
			//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		//} catch (Exception exc) {
		//	System.err.println("Error loading L&F: " + exc);
		//}
		init();
	}

	public static void main(String[] args) {
		YDesignEditor editor = new YDesignEditor();
	}

	public void init() {

		document.addUndoableEditListener(undoHandler);
		resetUndoManager();
		setLayout(new BorderLayout());
		textPane = new JTextPane(document);
		textPane.setContentType("text/html");
		JScrollPane scrollPane = new JScrollPane(textPane);
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		
		//toolPanel.add(editorControlPanel, BorderLayout.NORTH);
		add(scrollPane, BorderLayout.CENTER);
		//pack();
		//setLocationRelativeTo(null);
		startNewDocument();
		//show();
	}

	public void actionPerformed(ActionEvent ae) {
		String text = textPane.getText();
		System.out.println(text);
		String actionCommand = ae.getActionCommand();
		if (debug) {
			int modifier = ae.getModifiers();
			long when = ae.getWhen();
			String parameter = ae.paramString();
			System.out.println("actionCommand: " + actionCommand);
			System.out.println("modifier: " + modifier);
			System.out.println("when: " + when);
			System.out.println("parameter: " + parameter);
		}
		if (actionCommand.compareTo("New") == 0) {
			startNewDocument();
		} else if (actionCommand.compareTo("Open") == 0) {
			openDocument();
		} else if (actionCommand.compareTo("Save") == 0) {
			saveDocument();
		} else if (actionCommand.compareTo("Save As") == 0) {
			saveDocumentAs();
		} else if (actionCommand.compareTo("Exit") == 0) {
			exit();
		} else if (actionCommand.compareTo("Clear") == 0) {
			clear();
		} else if (actionCommand.compareTo("Select All") == 0) {
			selectAll();
		} else if (actionCommand.compareTo("Help") == 0) {
			help();
		} else if (actionCommand.compareTo("Keyboard Shortcuts") == 0) {
			showShortcuts();
		} else if (actionCommand.compareTo("About") == 0) {
			//aboutQuantumHyperSpace();
		}
	}

	protected void resetUndoManager() {
		undo.discardAllEdits();
		undoAction.update();
		redoAction.update();
	}

	public void startNewDocument() {
		Document oldDoc = textPane.getDocument();
		if (oldDoc != null)
			oldDoc.removeUndoableEditListener(undoHandler);
		HTMLEditorKit editorKit = new HTMLEditorKit();
		document = (HTMLDocument) editorKit.createDefaultDocument();
		textPane.setDocument(document);
		currentFile = null;
		//setTitle("HTMLDocumentEditor");
		textPane.getDocument().addUndoableEditListener(undoHandler);
		resetUndoManager();
	}

	public void openDocument() {
		try {
			File current = new File(".");
			JFileChooser chooser = new JFileChooser(current);
			chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
			chooser.setFileFilter(new YHTMLFileFilter());
			int approval = chooser.showSaveDialog(this);
			if (approval == JFileChooser.APPROVE_OPTION) {
				currentFile = chooser.getSelectedFile();
				//setTitle(currentFile.getName());
				FileReader fr = new FileReader(currentFile);
				Document oldDoc = textPane.getDocument();
				if (oldDoc != null)
					oldDoc.removeUndoableEditListener(undoHandler);
				HTMLEditorKit editorKit = new HTMLEditorKit();
				document = (HTMLDocument) editorKit.createDefaultDocument();
				editorKit.read(fr, document, 0);
				document.addUndoableEditListener(undoHandler);
				textPane.setDocument(document);
				resetUndoManager();
			}
		} catch (BadLocationException ble) {
			System.err.println("BadLocationException: " + ble.getMessage());
		} catch (FileNotFoundException fnfe) {
			System.err.println("FileNotFoundException: " + fnfe.getMessage());
		} catch (IOException ioe) {
			System.err.println("IOException: " + ioe.getMessage());
		}

	}

	public void saveDocument() {
		if (currentFile != null) {
			try {
				FileWriter fw = new FileWriter(currentFile);
				fw.write(textPane.getText());
				fw.close();
			} catch (FileNotFoundException fnfe) {
				System.err.println("FileNotFoundException: "
						+ fnfe.getMessage());
			} catch (IOException ioe) {
				System.err.println("IOException: " + ioe.getMessage());
			}
		} else {
			saveDocumentAs();
		}
	}

	public void saveDocumentAs() {
		try {
			File current = new File(".");
			JFileChooser chooser = new JFileChooser(current);
			chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
			chooser.setFileFilter(new YHTMLFileFilter());
			int approval = chooser.showSaveDialog(this);
			if (approval == JFileChooser.APPROVE_OPTION) {
				File newFile = chooser.getSelectedFile();
				if (newFile.exists()) {
					String message = newFile.getAbsolutePath()
							+ " already exists. \n"
							+ "Do you want to replace it?";
					if (JOptionPane.showConfirmDialog(this, message) == JOptionPane.YES_OPTION) {
						currentFile = newFile;
						//setTitle(currentFile.getName());
						FileWriter fw = new FileWriter(currentFile);
						fw.write(textPane.getText());
						fw.close();
						if (debug)
							System.out.println("Saved "
									+ currentFile.getAbsolutePath());
					}
				} else {
					currentFile = new File(newFile.getAbsolutePath());
					//setTitle(currentFile.getName());
					FileWriter fw = new FileWriter(currentFile);
					fw.write(textPane.getText());
					fw.close();
					if (debug)
						System.out.println("Saved "
								+ currentFile.getAbsolutePath());
				}
			}
		} catch (FileNotFoundException fnfe) {
			System.err.println("FileNotFoundException: " + fnfe.getMessage());
		} catch (IOException ioe) {
			System.err.println("IOException: " + ioe.getMessage());
		}
	}

	public void exit() {
		String exitMessage = "Are you sure you want to exit?";
		if (JOptionPane.showConfirmDialog(this, exitMessage) == JOptionPane.YES_OPTION) {
			System.exit(0);
		}
	}

	public void clear() {
		startNewDocument();
	}

	public void selectAll() {
		textPane.selectAll();
	}

	public void help() {
		JOptionPane.showMessageDialog(this, "TODO\n" );
	}

	public void showShortcuts() {
		String shortcuts = "Navigate in    |  Tab\n"

				+ "Navigate out   |  Ctrl+Tab\n"
				+ "Navigate out backwards    |  Shift+Ctrl+Tab\n"
				+ "Move up/down a line    |  Up/Down Arrown\n"
				+ "Move left/right a component or char    |  Left/Right Arrow\n"
				+ "Move up/down one vertical block    |  PgUp/PgDn\n"
				+ "Move to start/end of line    |  Home/End\n"
				+ "Move to previous/next word    |  Ctrl+Left/Right Arrow\n"
				+ "Move to start/end of data    |  Ctrl+Home/End\n"
				+ "Move left/right one block    |  Ctrl+PgUp/PgDn\n"
				+ "Select All    |  Ctrl+A\n"
				+ "Extend selection up one line    |  Shift+Up Arrow\n"
				+ "Extend selection down one line    |  Shift+Down Arrow\n"
				+ "Extend selection to beginning of line    |  Shift+Home\n"
				+ "Extend selection to end of line    |  Shift+End\n"
				+ "Extend selection to beginning of data    |  Ctrl+Shift+Home\n"
				+ "Extend selection to end of data    |  Ctrl+Shift+End\n"
				+ "Extend selection left    |  Shift+Right Arrow\n"
				+ "Extend selection right    |  Shift+Right Arrow\n"
				+ "Extend selection up one vertical block    |  Shift+PgUp\n"
				+ "Extend selection down one vertical block    |  Shift+PgDn\n"
				+ "Extend selection left one block    |  Ctrl+Shift+PgUp\n"
				+ "Extend selection right one block    |  Ctrl+Shift+PgDn\n"
				+ "Extend selection left one word    |  Ctrl+Shift+Left Arrow\n"
				+ "Extend selection right one word    |  Ctrl+Shift+Right Arrow\n";
		JOptionPane.showMessageDialog(this, shortcuts);
	}

	class UndoHandler implements UndoableEditListener {

		/**
		 * Messaged when the Document has created an edit, the edit is added to
		 * <code>undo</code>, an instance of UndoManager.
		 */
		public void undoableEditHappened(UndoableEditEvent e) {
			undo.addEdit(e.getEdit());
			undoAction.update();
			redoAction.update();
		}
	}

	class UndoAction extends AbstractAction {
		public UndoAction() {
			super("Undo");
			setEnabled(false);
		}

		public void actionPerformed(ActionEvent e) {
			try {
				undo.undo();
			} catch (CannotUndoException ex) {
				System.out.println("Unable to undo: " + ex);
				ex.printStackTrace();
			}
			update();
			redoAction.update();
		}

		protected void update() {
			if (undo.canUndo()) {
				setEnabled(true);
				putValue(Action.NAME, undo.getUndoPresentationName());
			} else {
				setEnabled(false);
				putValue(Action.NAME, "Undo");
			}
		}
	}

	class RedoAction extends AbstractAction {

		public RedoAction() {
			super("Redo");
			setEnabled(false);
		}

		public void actionPerformed(ActionEvent e) {
			try {
				undo.redo();
			} catch (CannotRedoException ex) {
				System.err.println("Unable to redo: " + ex);
				ex.printStackTrace();
			}
			update();
			undoAction.update();
		}

		protected void update() {
			if (undo.canRedo()) {
				setEnabled(true);
				putValue(Action.NAME, undo.getRedoPresentationName());
			} else {
				setEnabled(false);
				putValue(Action.NAME, "Redo");
			}
		}
	}
	
}
